package com.zzyl.nursing.service.impl;

import java.time.*;
import java.util.*;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.config.properties.AliIoTConfigProperties;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.dto.FamilyMemberDto;
import com.zzyl.nursing.dto.UserLoginRequestDto;
import com.zzyl.nursing.mapper.ContractMapper;
import com.zzyl.nursing.mapper.DeviceDataMapper;
import com.zzyl.nursing.mapper.ElderMapper;
import com.zzyl.nursing.service.WechatService;
import com.zzyl.nursing.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.FamilyMemberMapper;
import com.zzyl.nursing.service.IFamilyMemberService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 老人家属Service业务层处理
 * 
 * @author ruoyi
 * @date 2024-09-19
 */
@Service
@Slf4j
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper,FamilyMember> implements IFamilyMemberService {
    @Autowired
    private FamilyMemberMapper familyMemberMapper;

    @Autowired
    private WechatService wechatService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ElderMapper elderMapper;

    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private DeviceDataMapper deviceDataMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private Client client;

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;


    static List<String> DEFAULT_NICK_NAME = ListUtil.of(
            "生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝");

    /**
     * 小程序登录
     *
     * @param dto
     * @return
     */
    @Override
    public LoginVo login(UserLoginRequestDto dto) {

        //1.获取openid(调用微信的接口获取) ***
        String openid = wechatService.getOpenid(dto.getCode());

        //2.根据openid查询用户
        LambdaQueryWrapper<FamilyMember> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FamilyMember::getOpenId, openid);
        FamilyMember familyMember = getOne(queryWrapper);

        //3.判断用户是否存在，用户不存在，就构建用户
        if (ObjectUtil.isEmpty(familyMember)) {
            /*familyMember = new FamilyMember();
            familyMember.setOpenId(openid);*/
            familyMember = FamilyMember.builder()
                    .openId(openid)
                    .build();
        }

        //4.获取用户的手机号（调用微信的接口获取）***
        String phone = wechatService.getPhone(dto.getPhoneCode());

        //5. 新增或修改用户
        inserOrUpdateFamilyMember(familyMember, phone);

        //6. 把用户的信息封装到token,返回
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", familyMember.getName());
        claims.put("userId", familyMember.getId());
        String token = tokenService.createToken(claims);

        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setNickName(familyMember.getName());

        return loginVo;
    }

    /**
     * 新增或修改用户
     *
     * @param familyMember
     * @param phone
     */
    private void inserOrUpdateFamilyMember(FamilyMember familyMember, String phone) {

        //1. 判断新的手机跟数据库中保存的手机号是否一致
        if (ObjectUtil.notEqual(familyMember.getPhone(), phone)) {
            familyMember.setPhone(phone);
        }

        //2. id是否存在，如存在，就修改
        if (ObjectUtil.isNotEmpty(familyMember.getId())) {
            updateById(familyMember);
            return;
        }

        //3. 不存在，就新增 (拼装用户的昵称：随机字符串+手机号后4位)
        int index = (int) (Math.random() * DEFAULT_NICK_NAME.size());
        String nickName = DEFAULT_NICK_NAME.get(index) + phone.substring(phone.length() - 4);
        familyMember.setName(nickName);
        save(familyMember);

    }

    /**
     * 查询老人家属
     *
     * @param id 老人家属主键
     * @return 老人家属
     */
    @Override
    public FamilyMember selectFamilyMemberById(Long id) {
        return getById(id);
    }

    /**
     * 查询老人家属列表
     *
     * @param familyMember 老人家属
     * @return 老人家属
     */
    @Override
    public List<FamilyMember> selectFamilyMemberList(FamilyMember familyMember) {
        return familyMemberMapper.selectFamilyMemberList(familyMember);
    }

    /**
     * 新增老人家属
     *
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int insertFamilyMember(FamilyMember familyMember) {
        return save(familyMember) ? 1 : 0;
    }

    /**
     * 修改老人家属
     *
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int updateFamilyMember(FamilyMember familyMember) {
        return updateById(familyMember) ? 1 : 0;
    }

    /**
     * 批量删除老人家属
     *
     * @param ids 需要删除的老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除老人家属信息
     *
     * @param id 老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberById(Long id) {
        return removeById(id) ? 1 : 0;
    }

    /**
     * 绑定老人
     *
     * @param familyMemberDto
     */
    @Override
    public void addFamilyElder(FamilyMemberDto familyMemberDto) {

        //1.判断是否登录
        //从线程局部变量中获取用户id
        Long userId = UserThreadLocal.get();

        if (ObjectUtil.isEmpty(userId)) {
            throw new RuntimeException("请先登录");
        }

        //2.判断familyMemberDto是否为空
        if (ObjectUtil.isEmpty(familyMemberDto)) {
            throw new BaseException("绑定信息不能为空");
        }
        //3.判断身份证格式是否正确
        String idCard = familyMemberDto.getIdCard();

        //if(!IdcardUtil.isValidCard(idCard)){
        if (idCard.length() != 18) {
            throw new BaseException("身份证格式不正确");
        }
        //4判断该老人是否签订了合同
        //根据老人查询老人的id
        Elder elder = elderMapper.selectOne(Wrappers.<Elder>lambdaQuery().eq(Elder::getIdCardNo, idCard));
        if (ObjectUtil.isEmpty(elder)) {
            throw new BaseException("该老人不存在");
        }
        //根据老人的id查询是否有合同
        Contract contract = contractMapper.selectOne(Wrappers.<Contract>lambdaQuery().eq(Contract::getElderId, elder.getId())
                .eq(Contract::getStatus, 1));
        if (ObjectUtil.isEmpty(contract)) {
            throw new BaseException("该老人未签合同或合同过期");
        }

        //5.判断当前微信用户是否已经绑定了老人
        Long elderId = familyMemberMapper.isAddFamilyElder(userId, elder.getId());
        if (ObjectUtil.isNotEmpty(elderId)) {
            throw new BaseException("当前用户已绑定老人");
        }
        LocalDateTime createTime = LocalDateTime.now();
        //6.将老人的id和当前用户的id绑定到关联表中
        familyMemberMapper.addElder(userId, elder.getId(), familyMemberDto.getRemark(), createTime);

    }

    /**
     * 查询我的老人
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public List<FamilyElderVo> selectMy(Integer pageNum, Integer pageSize) {

        return familyMemberMapper.selectFamilyElderList(pageNum, pageSize);
    }


    /**
     * 分页查询
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public List<FamilyElderListVo> getByPage(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        Long userId = UserThreadLocal.get();


        Page<FamilyElderListVo> page = familyMemberMapper.getByPage(pageNum, pageSize,userId);
        List<FamilyElderListVo> result = page.getResult();

        return result;
    }

    /**
     * 查看健康数据
     *
     * @param deviceDto
     * @return
     */
    @Override
    public List<PropertyStatusInfo> QueryDevicePropertyStatus(DeviceDto deviceDto) {

        List<DeviceData> deviceData = deviceDataMapper.selectList(Wrappers.<DeviceData>lambdaQuery().eq(DeviceData::getDeviceName, deviceDto.getDeviceName())
                .eq(DeviceData::getProductKey, deviceDto.getProductKey()));
        if (ObjectUtil.isEmpty(deviceData)) {
            throw new BaseException("设备不存在");
        }
        //从redis中获取设备数据
        String jsonPrettyStr = JSONUtil.toJsonStr(redisTemplate.opsForHash().get(CacheConstants.IOT_DEVICE_LAST_DATA, deviceData.get(0).getIotId()));
        List<DeviceData> list1 = JSONUtil.toList(jsonPrettyStr, DeviceData.class);

        List<PropertyStatusInfo> list = new ArrayList<>();
        list1.forEach(d -> {
                    log.info(d.toString());
                    LocalDateTime alarmTime = d.getAlarmTime();
                    //将时间转换为毫秒
                    long time = alarmTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
                        list.add(new PropertyStatusInfo(null, d.getFunctionId(), null, time, null, d.getDataValue()));
                }
        );
        return list;
    }

    /**
     * 按天统计查询指标数据
     *
     * @param iotId
     * @param functionId
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public DeviceDataDayVo queryDeviceDataListByDay(String iotId, String functionId, Long startTime, Long endTime) {
        // 将 startTime 和 endTime 转换为 LocalDateTime
        LocalDateTime time1 = LocalDateTimeUtil.of(startTime);
        LocalDateTime time2 = LocalDateTimeUtil.of(endTime);

        // 查询数据库中的数据
        List<DeviceData> deviceData = deviceDataMapper.selectList(Wrappers.<DeviceData>lambdaQuery()
                .eq(DeviceData::getIotId, iotId)
                .eq(DeviceData::getFunctionId, functionId)
                .between(DeviceData::getAlarmTime, time1, time2));

        if (ObjectUtil.isEmpty(deviceData)) {
            throw new BaseException("设备不存在或者设备损坏");
        }

        // 创建一个 Map 来存储每个小时的第一条数据
        Map<Integer, DataAndValue> hourlyDataMap = new HashMap<>();

        // 遍历 deviceData 列表，根据 alarmTime 的小时部分将数据添加到 Map 中
        for (DeviceData d : deviceData) {
            LocalDateTime alarmTime = d.getAlarmTime();
            int hour = alarmTime.getHour();
            if (!hourlyDataMap.containsKey(hour)) {
                LocalTime localTime = alarmTime.toLocalTime();
                hourlyDataMap.put(hour, new DataAndValue(localTime, d.getDataValue()));
            }
        }

        // 确保每个小时都有一个条目，如果没有数据则设置值为 null
        List<DataAndValue> list = new ArrayList<>();
        for (int hour = 0; hour < 24; hour++) {
            list.add(hourlyDataMap.getOrDefault(hour, new DataAndValue(LocalTime.of(hour, 0), null)));
        }

        // 创建 DeviceDataDayVo 对象并设置列表
        DeviceDataDayVo deviceDataDayVo = new DeviceDataDayVo();
        deviceDataDayVo.setList(list);

        return deviceDataDayVo;
    }


    /**
     * 按周统计查询指标数据
     *
     * @param iotId
     * @param functionId
     * @param startTime
     * @param endTime
     * @return
     */

@Override

    public DataAndValueWeekVo queryDeviceDataListByWeek(String iotId, String functionId, Long startTime, Long endTime) {
        // 将 startTime 和 endTime 转换为 LocalDateTime
        LocalDateTime time1 = LocalDateTimeUtil.of(startTime);
        LocalDateTime time2 = LocalDateTimeUtil.of(endTime);

        // 查询数据库中的数据
        List<DeviceData> deviceData = deviceDataMapper.selectList(Wrappers.<DeviceData>lambdaQuery()
                .eq(DeviceData::getIotId, iotId)
                .eq(DeviceData::getFunctionId, functionId)
                .between(DeviceData::getAlarmTime, time1, time2));

        // 创建一个 Map 来存储每天的第一条数据
        Map<LocalDate, DataAndValueWeek> dailyDataMap = new HashMap<>();
        deviceData.forEach(d -> {
            LocalDateTime alarmTime = d.getAlarmTime();
            LocalDate date = alarmTime.toLocalDate();
            if (!dailyDataMap.containsKey(date)) {
                LocalTime localTime = alarmTime.toLocalTime();
                dailyDataMap.put(date, new DataAndValueWeek(date, d.getDataValue()));
            }
        });

        // 如果当天没有数据,则设置value值为null
        List<DataAndValueWeek> list = new ArrayList<>();
        LocalDate startDate = time1.toLocalDate();
        for (int i = 0; i < 7; i++) {
            LocalDate currentDate = startDate.plusDays(i);
            list.add(dailyDataMap.getOrDefault(currentDate, new DataAndValueWeek(currentDate, null)));
        }

    DataAndValueWeekVo dataAndValueWeekVo = new DataAndValueWeekVo();
    dataAndValueWeekVo.setList(list);

        return dataAndValueWeekVo;
    }

/*    public DeviceDataDayVo queryDeviceDataListByWeek(String iotId, String functionId, Long startTime, Long endTime) {
        // 将 startTime 和 endTime 转换为 LocalDateTime
        LocalDateTime time1 = LocalDateTimeUtil.of(startTime);
        LocalDateTime time2 = LocalDateTimeUtil.of(endTime);

        // 查询数据库中的数据
        List<DeviceData> deviceData = deviceDataMapper.selectList(Wrappers.<DeviceData>lambdaQuery()
                .eq(DeviceData::getIotId, iotId)
                .eq(DeviceData::getFunctionId, functionId)
                .between(DeviceData::getAlarmTime, time1, time2));
        // 创建一个 Map 来存储每天的第一条数据
        Map<Integer, DataAndValue> daylyDataMap = new HashMap<>();
        deviceData.forEach(d -> {
            LocalDateTime alarmTime = d.getAlarmTime();
            int day = alarmTime.getDayOfWeek().getValue();
            if (!daylyDataMap.containsKey(day)) {
                LocalTime localTime = alarmTime.toLocalTime();
                daylyDataMap.put(day, new DataAndValue(localTime, d.getDataValue()));
            }
        });

        //如果当天没有数据,则设置value值为null
        List<DataAndValue> list = new ArrayList<>();
        for (int day = 1; day <= 7; day++) {
            list.add(daylyDataMap.getOrDefault(day, new DataAndValue(LocalTime.of(day, 0), null)));
        }
        DeviceDataDayVo deviceDataDayVo = new DeviceDataDayVo();
        deviceDataDayVo.setList(list);

        return deviceDataDayVo ;
    }*/
}

